import { Color, color, Component, Graphics, UITransform, v3, Vec2, _decorator } from 'cc';
import { Loger } from '../../loger/Loger';
import LocalStorage from '../../utils/LocalStorage';
import { AStarGrid, AStarGridType, AStarMapData } from './AStarData';
import { AStarLogic } from './AStarLogic';

/**A星寻路地图生成器 */
const { ccclass, menu, property } = _decorator;
@ccclass
@menu("AStar/AStarMapGenerator")
export class AStarMapGenerator extends Component {

    @property({ tooltip: "格子颜色-普通" })
    private colorNormal: Color = color(0, 0, 0, 0)
    @property({ tooltip: "格子颜色-障碍" })
    private colorObstacles: Color = color(255, 0, 0, 150)
    @property({ tooltip: "格子颜色-起点" })
    private colorStart: Color = color(255, 255, 0, 150)
    @property({ tooltip: "格子颜色-终点" })
    private colorEnd: Color = color(0, 0, 255, 150)
    @property({ tooltip: "格子颜色-路径" })
    private colorPath: Color = color(0, 255, 0, 150)
    @property({ type: AStarLogic, tooltip: "A*逻辑" })
    aStarLogic: AStarLogic = null;
    @property({ type: Graphics, tooltip: "绘制格子组件" })
    public map: Graphics = null;
    @property({ tooltip: "格子宽度" })
    public gridW: number = 50;
    @property({ tooltip: "格子高度" })
    public gridH: number = 50;
    @property({ tooltip: "是否8方向查找" })
    public is8dir: boolean = true;

    public mapH: number;
    public mapW: number;

    private startPos: Vec2;
    private endPos: Vec2;


    start() {
        // this._logic = AStarLogic.getInstance();
        const uiTrans = this.node.getComponent(UITransform);
        this.mapH = Math.round(uiTrans.height / this.gridH);     // 纵向格子数量
        this.mapW = Math.round(uiTrans.width / this.gridW);     // 横向格子数量

        this.is8dir = true; // 是否8方向寻路
        this.map = this.getComponent(Graphics);

        this.initMap();
    }

    public reset() {
        let data: AStarMapData = this._initMapData();
        this.aStarLogic.init(data);
        this.save();
        this.drawAll();
    }

    private _initMapData(): AStarMapData {
        let data: AStarMapData = {
            gridW: this.gridW,
            gridH: this.gridH,
            mapW: this.mapW,
            mapH: this.mapH,
            is8dir: this.is8dir,
            gridsType: new Array(this.mapW),
        }

        for (let col = 0; col < this.mapW; col++) {
            if (!data.gridsType[col]) {
                data.gridsType[col] = new Array(this.mapH)
            }
            for (let row = 0; row < this.mapH; row++) {
                data.gridsType[col][row] = AStarGridType.Obstacles;
            }
        }
        return data;
    }

    initMap() {

        // let mapData = LocalStorage.getString("map", "")
        let mapData = null// ConfigMgr.getInstance().mapCfg;

        let data: AStarMapData = null;

        if (mapData == null) {
            data = this._initMapData();
        } else {
            data = mapData
            if (data.gridW != this.gridW || data.gridH != this.gridH) {
                data = this._initMapData();
            }
        }
        this.aStarLogic.init(data);
        this.save();
        this.drawAll();
    }


    public save() {
        let data = JSON.stringify(this.aStarLogic.data);
        Loger.log("map data: ", data);
        LocalStorage.setString("map", data);
    }

    public getClickNodeGridType(worldPos: Vec2): AStarGridType {
        let parentUITrans = this.node.parent.getComponent(UITransform);
        let nodePos = parentUITrans.convertToNodeSpaceAR(v3(worldPos.x, worldPos.y));
        let gridPos = this.aStarLogic.getMapGridPos(nodePos);
        return this.aStarLogic.getGridType(gridPos.x, gridPos.y)
    }

    public onClick(worldPos: Vec2, type: AStarGridType, targetType?: AStarGridType) {
        let parentUITrans = this.node.parent.getComponent(UITransform);
        let nodePos = parentUITrans.convertToNodeSpaceAR(v3(worldPos.x, worldPos.y));
        let gridPos = this.aStarLogic.getMapGridPos(nodePos);
        Loger.log(`=====Click Grid====>> ${JSON.stringify(gridPos)}`)
        if (type == AStarGridType.Obstacles) {
            if (targetType == null) {
                if (this.aStarLogic.getGridType(gridPos.x, gridPos.y) == AStarGridType.Normal) {
                    this.aStarLogic.setGridType(gridPos.x, gridPos.y, AStarGridType.Obstacles);
                } else if (this.aStarLogic.getGridType(gridPos.x, gridPos.y) == AStarGridType.Obstacles) {
                    this.aStarLogic.setGridType(gridPos.x, gridPos.y, AStarGridType.Normal);
                }
            } else {
                this.aStarLogic.setGridType(gridPos.x, gridPos.y, targetType);
            }
        } else if (type == AStarGridType.Start) {
            if (this.startPos && this.startPos.x == gridPos.x && this.startPos.y == gridPos.y) {
                this.startPos = null;
            } else {
                this.startPos = gridPos;
            }
        } else if (type == AStarGridType.End) {
            if (this.endPos && this.endPos.x == gridPos.x && this.endPos.y == gridPos.y) {
                this.endPos = null;
            } else {
                this.endPos = gridPos;
            }
        }
        this.drawAll();
    }

    public onFindPath() {
        // 开始寻路
        // this.findPath(v2(3, 8), v2(19, 5));
        if (!this.startPos || !this.endPos) {
            Loger.error("没有选择起点或终点");
            return;
        }
        let path = this.aStarLogic.findPathNoRightAngle(this.startPos, this.endPos);
        this.drawPath(path);
    }


    draw(col: number, row: number, color?: Color) {
        color = color != undefined ? color : this.colorNormal;
        this.map.fillColor = color;
        let posX = col * this.gridW;
        let posY = row * this.gridH;
        // let posX = 2 + col * (this._gridW + 2);
        // let posY = 2 + row * (this._gridH + 2);
        // this.map.fillRect(posX, posY, this.gridW, this.gridH);
        this.map.rect(posX, posY, this.gridW, this.gridH)
        this.map.strokeColor = Color.BLACK;
        this.map.lineWidth = 1.5;
        this.map.stroke();
        this.map.fill();
    }

    drawPath(path: AStarGrid[]) {
        if (!path || path.length == 0) {
            Loger.log("找不到路径")
            return;
        }
        for (let i = 0; i < path.length; i++) {
            // 起点终点不覆盖，方便看效果
            if (i != 0 && i != path.length - 1) {
                let grid = path[i];
                this.draw(grid.x, grid.y, this._getColor());
            }
        }
    }

    drawAll() {
        this.map.clear();
        for (let col = 0; col < this.aStarLogic.gridsList.length; col++) {
            for (let row = 0; row < this.aStarLogic.gridsList[col].length; row++) {
                let grid = this.aStarLogic.gridsList[col][row];
                if (this.startPos && grid.x == this.startPos.x && grid.y == this.startPos.y) {
                    this.draw(col, row, this._getColor(AStarGridType.Start));
                } else if (this.endPos && grid.x == this.endPos.x && grid.y == this.endPos.y) {
                    this.draw(col, row, this._getColor(AStarGridType.End));
                } else {
                    this.draw(col, row, this._getColor(grid.type));
                }
            }
        }
    }

    private _getColor(type?: AStarGridType) {
        switch (type) {
            case AStarGridType.Normal:
                return this.colorNormal;
                break;
            case AStarGridType.Obstacles:
                return this.colorObstacles;
                break;
            case AStarGridType.Start:
                return this.colorStart;
                break;
            case AStarGridType.End:
                return this.colorEnd;
                break;
            default:
                return this.colorPath;
                break;
        }
    }
}